/* @(#)defense.c
 * Time-stamp: <2008-10-25 21:43:00 root>
 * Copyright 2008 Julian Qian
 * Author: root@localhost.localdomain
 * Version: $Id: alarm.c,v 0.0 2008/10/05 14:52:54 root Exp $
 * Keywords: 
 */

#include "common.h"

void alarm_user_thread(PHONE_PAIR *pp){
	ws_alarm(pp);
	pthread_exit(0);
}

/* alarm by web service */
int ws_alarm(PHONE_PAIR *pp){
	char cmd[50];
	if(pp->alarm == ALARM_MANUA_USER ||
	   pp->alarm == ALARM_DOORR_USER ||
	   pp->alarm == ALARM_INFRA_USER){
		sprintf(cmd, "php ./esms.php -send %s,%d", pp->phone, pp->alarm);
		err_msg(cmd);
		return system(cmd);
	}else{
		return -1;
	}
}

// return number of phone pairs
int ws_alarm_recv(PHONE_PAIR **pp, int max){
	char cmd[50];
	sprintf(cmd, "php ./esms.php -receive");
	system(cmd);
	/* err_msg(cmd); */

	char *pch;
	char pstr[SHM_ESMS_SIZE];
	

	int shm_id;
	key_t shm_key;
	char *str_map;
	
	char shm_dev[] = SHM_DEVICE;
	if((shm_key = ftok(shm_dev, 't')) == -1){
		perror("ftok error!");
		return -1;
	}
	shm_id = shmget(shm_key, SHM_ESMS_SIZE, 0644 | IPC_CREAT);
	if(shm_id == -1){
		perror("shmget failed!");
		return -1;		
	}
	str_map = (char *)shmat(shm_id, NULL, 0);
	
	/* $info format: 1331331334:msg1,1321321323:msg2,.. */

	strncpy(pstr, str_map, SHM_ESMS_SIZE);

	/* printf("$$DEFENSE!\n SHARE memory: -->%s<--\n", str_map); */

	memset(str_map, 0, SHM_ESMS_SIZE);

	if(shmdt(str_map) == -1){
		perror("detach failed!");
		return -1;		
	}

	// get phone pairs
	pch = strtok(pstr, ":,");
	int i = 0;

	while( pch != NULL && i < max){
		// get phone, by colon
		strncpy(pp[i]->phone, pch, PHONE_SIZE);
		pch = strtok(NULL, ":,");

		if(pch == NULL) break;
		// get alarm, by comma
		if(strncasecmp(pch, USER_DEFEN_MSG, sizeof(USER_DEFEN_MSG)) == 0){
			pp[i]->alarm = USER_DEFEN;
		}else if(strncasecmp(pch, USER_UNDEF_MSG, sizeof(USER_UNDEF_MSG)) == 0){
			pp[i]->alarm = USER_UNDEF;
		}else{
			pp[i]->alarm = USER_NULL;
		}
		
		pch = strtok(NULL, ":,");
		err_msg("%d) phone: %s, alarm: %x",i, pp[i]->phone, pp[i]->alarm);

		i++;
	}
	return i;
}

void defense_run(){
	PHONE_PAIR *pp = (PHONE_PAIR *)malloc(200 * sizeof(PHONE_PAIR));
	int ps, i;
	if( -1 == (ps = ws_alarm_recv(&pp, 200)) ) {
		/* error */
		return;
	}

	int defen_id, len, ret;
	devid_t devid = 0;
	ip_t ip = 0;
	struct sockaddr_in client_addr;
	char buffer[PROTO_LENG];
	memset(buffer, 0, sizeof(buffer));
	
	defen_id = Socket(AF_INET, SOCK_DGRAM, 0);

	/* Set exipred time */
	struct timeval tv;
	tv.tv_sec = 3;
	tv.tv_usec = 0;
	Setsockopt(defen_id, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); /* SO_RECVTIMEO */
	
	for (i =0; i< ps; i++) {

		err_msg("defense_run: %d) %s: %x", i, pp[i].phone, pp[i].alarm);
		/* Search client ip & device id by mobile phone before send command */
		/* 1) client devicd ID */
		strncpy(gDBQ_Defen.sel_devid_phone, pp[i].phone, PHONE_SIZE);
		gDBQ_Defen.sel_devid_phone_len = strlen(pp[i].phone);
		mutex_lock(gDBQ_Defen.mutex);
		db_stmt_query(gDBQ_Defen.sel_devid_stmt);
		devid = db_stmt_sel_devid(&gDBQ_Defen);
		mutex_unlock(gDBQ_Defen.mutex);
		if( -1 == devid ) {
			/* ERROR: miss devid from phone */
			err_msg( "Fetch devid by phone num failed!");
			break;
		}
		
		/* 2) client IP address */
		/* fetch from hash table firstly */
		KEY *k;
		VALUE *found;
		k = (KEY*) malloc(sizeof(KEY));
		k->devid = devid;

		if(NULL != ( found = (VALUE*)search_some(gHash, k))){
			ip = found->ip;
			err_msg("Found in hash table! %d", k->devid, ip);
			free(k);
		}else{
			gDBQ_Defen.sel_ip_devid = devid;
			mutex_lock(gDBQ_Defen.mutex);
			db_stmt_query(gDBQ_Defen.sel_ip_stmt);
			ip = db_stmt_sel_ip(&gDBQ_Defen);
			mutex_unlock(gDBQ_Defen.mutex);
			
			if( 0 == ip ){
				/* ERROR: miss IP from devid */
				err_msg( "NOT EXISTS! Fetch IP by devid interupted!");
				break;
			}
		}
		/* if(!ip) ip = 2840713683; */
		/* if(!ip) ip = 3554234793; */

		err_msg("OBTAIN devid->%d, ip->%s", devid, IP(ip));
		/* $$$$$$$$$$$$$$$$ */
		/* combine buffer package */
		/* 1: length */
		buffer[0] = 0x0C;
		/* 2~3: Device board address */
		buffer[1] = 0x00;
		buffer[2] = 0x28;
		/* 4~6: Device Unique ID */
		cvt_di(devid, buffer + PROTO_DEVI);
		/* 7~8: device version */
		buffer[6] = 0x01;
		buffer[7] = 0x00;
		/* 9~10: function description */
		buffer[8] = 0xf0;
		buffer[9] = 0x00;
		/* 11~12: Reserved */
		buffer[10] = 0x00;
		buffer[11] = 0x00;
		/* 13~14: sequance number */
		buffer[12] = 0x00;
		buffer[13] = 0x00;
		/* 15: data length */
		buffer[14] = 0x02;
		/* 16: data type */
		buffer[15] = 0x07;  /* send from server */
		/* 17: data detail */
		buffer[16] = pp[i].alarm;

		/* $$$$$$$$$$$$$$$$ */
		/* combile client address */
		memset(&client_addr, 0, sizeof(client_addr));
		client_addr.sin_family = AF_INET;
		client_addr.sin_addr.s_addr = htonl(ip);
		client_addr.sin_port = htons(CLIENT_PORT);

		err_msg( "$$$$$$$$$$$$$$$$SEND COMMAND TO CLIENT DEFENSE: %s, %x $$$$$$$$$$$$$$$$", IP(ip), buffer[PROTO_DATA]);
		fflush(stdout);
		
		/* $$$$$$$$$$$$$$$$ */
		/* send defense command to client */
		sendto(defen_id, buffer, PROTO_LENG, 0, (SA *)&client_addr, (len = sizeof(client_addr)));
		/* TODO: expired time */
		ret = recvfrom(defen_id, buffer, PROTO_LENG, 0, NULL, NULL);
		if(ret < 0){
			if(errno == EWOULDBLOCK){
				err_msg("Socket timeout.");
			}else{
				err_msg("Recvfrom failed!");
			}
		}else if(ret != PROTO_LENG ){
			/* receive error */
		}
	}

	close(defen_id);
	free(pp);
}

void Defense_obsolete(){

	int res = 0;
	
	Signal(SIGALRM, defense_run);

	struct itimerval tick;
	memset(&tick, 0, sizeof(tick));

	/* Timeout to run function first time  */
	tick.it_value.tv_sec = 10;
	tick.it_value.tv_usec = 0;
	
	/* Interval time to run function   */
	tick.it_interval.tv_sec = 10; /* sec */
	tick.it_interval.tv_usec = 0; /* micro sec */

	/* Set timer, ITIMER_REAL : real-time to decrease timer, */
	                         /* send SIGALRM when timeout   */
	res = setitimer(ITIMER_REAL, &tick, NULL);
	if(res){
		err_msg( "Set timer failed!!");
	}

	while(1){
		/* every 1 min */
		err_msg("DEFENSE Engine come!");
		pause();
	}

	exit(0);
}

void Defense(){
	disp_t td = DISPATCH_DEFENSE;
	gDispatcher &= ~td;

	defense_run();
}
